#include "../sys/vid_impl.h"
#include "../common/com_console.h"
#include "resource.h"

#include <windows.h>
#include <gl\gl.h>
#include <gl\glu.h>
#include <gl\glaux.h>
#include <stdio.h>

#define WINDOW_CLASS_NAME "OpenGL Test"
#define WINDOW_TITLE "OpenGL Test"

typedef struct
{
	HDC			hDC;
	HGLRC		hRC;
	HWND		hWnd;
	HINSTANCE	hInstance;

	bool	fullscreen;
}TWindowConfig;

TWindowConfig wndCfg;

extern LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int InitGL()										// All Setup For OpenGL Goes Here
{
	glShadeModel(GL_SMOOTH);							// Enable Smooth Shading
	glClearColor(0.0f, 0.0f, 0.0f, 0.5f);				// Black Background
	glClearDepth(1.0f);									// Depth Buffer Setup
	glEnable(GL_DEPTH_TEST);							// Enables Depth Testing
	glDepthFunc(GL_LEQUAL);								// The Type Of Depth Testing To Do
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);	// Really Nice Perspective Calculations
	return TRUE;										// Initialization Went OK
}

int vid_init()
{
	int width = 640;//(int)config->getValue("vid_width").asNumber;
	int height = 480;//(int)config->getValue("vid_height").asNumber;
	int bits = 32;//(int)config->getValue("vid_bpp").asNumber;

	GLuint		PixelFormat;
	WNDCLASS	wc;
	DWORD		dwExStyle;
	DWORD		dwStyle;
	RECT		WindowRect;

	WindowRect.left=(long)0;
	WindowRect.right=(long)width;
	WindowRect.top=(long)0;				
	WindowRect.bottom=(long)height;

	wndCfg.fullscreen=0;//(config->getValue("vid_fullscreen").asNumber!=0);

	wndCfg.hInstance	= GetModuleHandle(NULL);				// Grab An Instance For Our Window
	wc.style			= 0;
	wc.lpfnWndProc		= (WNDPROC) WndProc;					// WndProc Handles Messages
	wc.cbClsExtra		= 0;									// No Extra Window Data
	wc.cbWndExtra		= 0;									// No Extra Window Data
	wc.hInstance		= wndCfg.hInstance;							// Set The Instance
	wc.hIcon			= LoadIcon( wndCfg.hInstance, MAKEINTRESOURCE(IDI_ICON1));// Load The Default Icon
	wc.hCursor			= LoadCursor(NULL, IDC_ARROW);			// Load The Arrow Pointer
	wc.hbrBackground	= NULL;									// No Background Required For GL
	wc.lpszMenuName		= NULL;									// We Don't Want A Menu
	wc.lpszClassName	= WINDOW_CLASS_NAME;								// Set The Class Name

	if (!RegisterClass(&wc))									// Attempt To Register The Window Class
	{
		com_error("Failed To Register The Window Class.");
		return FALSE;
	}
	
	if (wndCfg.fullscreen)												// Attempt Fullscreen Mode?
	{
		DEVMODE dmScreenSettings;								// Device Mode
		memset(&dmScreenSettings,0,sizeof(dmScreenSettings));	// Makes Sure Memory's Cleared
		dmScreenSettings.dmSize=sizeof(dmScreenSettings);		// Size Of The Devmode Structure
		dmScreenSettings.dmPelsWidth	= width;				// Selected Screen Width
		dmScreenSettings.dmPelsHeight	= height;				// Selected Screen Height
		dmScreenSettings.dmBitsPerPel	= bits;					// Selected Bits Per Pixel
		dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

		// Try To Set Selected Mode And Get Results.  NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
		if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
		{
			com_error("The specified video mode (%dx%dx%d)is not supported.",width, height, bits);
				return FALSE;									// Return FALSE
		}
	}

	if (wndCfg.fullscreen)
	{
		dwExStyle=WS_EX_TOPMOST;
		dwStyle=WS_POPUP|WS_VISIBLE|WS_SYSMENU;
		ShowCursor(FALSE);
	}
	else
	{
		dwExStyle=0;
		dwStyle=WS_OVERLAPPED|WS_BORDER|WS_CAPTION|WS_VISIBLE|WS_SYSMENU|WS_MINIMIZEBOX;
	}

	int xPos = 100;//(int)config->getValue("vid_xpos").asNumber;
	int yPos = 100;//(int)config->getValue("vid_ypos").asNumber;


	AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);

	if (!(wndCfg.hWnd=CreateWindowEx(	dwExStyle,							// Extended Style For The Window
								WINDOW_CLASS_NAME,							// Class Name
								WINDOW_TITLE,								// Window Title
								dwStyle,					// Required Window Style
								xPos, yPos,								// Window Position
								WindowRect.right-WindowRect.left,	// Calculate Window Width
								WindowRect.bottom-WindowRect.top,	// Calculate Window Height
								NULL,								// No Parent Window
								NULL,								// No Menu
								wndCfg.hInstance,							// Instance
								NULL)))								// Dont Pass Anything To WM_CREATE
	{
		vid_shutdown();								// Reset The Display
		com_error("Could not create window.");
		return FALSE;								// Return FALSE
	}

	static	PIXELFORMATDESCRIPTOR pfd=				// pfd Tells Windows How We Want Things To Be
	{
		sizeof(PIXELFORMATDESCRIPTOR),				// Size Of This Pixel Format Descriptor
		1,											// Version Number
		PFD_DRAW_TO_WINDOW |						// Format Must Support Window
		PFD_SUPPORT_OPENGL |						// Format Must Support OpenGL
		PFD_DOUBLEBUFFER,							// Must Support Double Buffering
		PFD_TYPE_RGBA,								// Request An RGBA Format
		bits,										// Select Our Color Depth
		0, 0, 0, 0, 0, 0,							// Color Bits Ignored
		0,											// No Alpha Buffer
		0,											// Shift Bit Ignored
		0,											// No Accumulation Buffer
		0, 0, 0, 0,									// Accumulation Bits Ignored
		16,											// 16Bit Z-Buffer (Depth Buffer)  
		0,											// No Stencil Buffer
		0,											// No Auxiliary Buffer
		PFD_MAIN_PLANE,								// Main Drawing Layer
		0,											// Reserved
		0, 0, 0										// Layer Masks Ignored
	};
	
	if (!(wndCfg.hDC=GetDC(wndCfg.hWnd)))
	{
		vid_shutdown();								// Reset The Display
		com_error("Can't Create A GL Device Context.");
		return FALSE;								// Return FALSE
	}

	if (!(PixelFormat=ChoosePixelFormat(wndCfg.hDC,&pfd)))	// Did Windows Find A Matching Pixel Format?
	{
		vid_shutdown();								// Reset The Display
		com_error("Can't Find A Suitable PixelFormat.");
		return FALSE;								// Return FALSE
	}

	if(!SetPixelFormat(wndCfg.hDC,PixelFormat,&pfd))		// Are We Able To Set The Pixel Format?
	{
		vid_shutdown();								// Reset The Display
		com_error("Can't Set The PixelFormat.");
		return FALSE;								// Return FALSE
	}

	if (!(wndCfg.hRC=wglCreateContext(wndCfg.hDC)))				// Are We Able To Get A Rendering Context?
	{
		vid_shutdown();								// Reset The Display
		com_error("Can't Create A GL Rendering Context.");
		return FALSE;								// Return FALSE
	}

	if(!wglMakeCurrent(wndCfg.hDC,wndCfg.hRC))					// Try To Activate The Rendering Context
	{
		vid_shutdown();								// Reset The Display
		com_error("Can't Activate The GL Rendering Context.");
		return FALSE;								// Return FALSE
	}

	ShowWindow(wndCfg.hWnd,SW_SHOW);						// Show The Window
	SetForegroundWindow(wndCfg.hWnd);						// Slightly Higher Priority
	SetFocus(wndCfg.hWnd);									// Sets Keyboard Focus To The Window
	vid_resize(width, height);					// Set Up Our Perspective GL Screen

	if (!InitGL())									// Initialize Our Newly Created GL Window
	{
		vid_shutdown();								// Reset The Display
		com_error("Initialization Failed.");
		return FALSE;								// Return FALSE
	}

	return TRUE;									// Success
}

int vid_shutdown()
{
	if (wndCfg.fullscreen)										// Are We In Fullscreen Mode?
	{
		ChangeDisplaySettings(NULL,0);					// If So Switch Back To The Desktop
		ShowCursor(TRUE);								// Show Mouse Pointer
	}

	if (wndCfg.hRC)											// Do We Have A Rendering Context?
	{
		if (!wglMakeCurrent(NULL,NULL))					// Are We Able To Release The DC And RC Contexts?
		{
			com_error("Release Of DC And RC Failed.");
		}

		if (!wglDeleteContext(wndCfg.hRC))						// Are We Able To Delete The RC?
		{
			com_error("Release Rendering Context Failed.");
		}
		wndCfg.hRC=NULL;										// Set RC To NULL
	}

	if (wndCfg.hDC && !ReleaseDC(wndCfg.hWnd,wndCfg.hDC))					// Are We Able To Release The DC
	{
		com_error("Release Device Context Failed.");
		wndCfg.hDC=NULL;										// Set DC To NULL
	}

	if (wndCfg.hWnd && !DestroyWindow(wndCfg.hWnd))					// Are We Able To Destroy The Window?
	{
		com_error("Could Not Release hWnd.");
		wndCfg.hWnd=NULL;										// Set hWnd To NULL
	}

	if (!UnregisterClass(WINDOW_CLASS_NAME,wndCfg.hInstance))			// Are We Able To Unregister Class
	{
		com_error("Could Not Unregister Class.");
		wndCfg.hInstance=NULL;									// Set hInstance To NULL
	}

	return 0;
}

int vid_switchFrame()
{
	SwapBuffers(wndCfg.hDC);					// Swap Buffers (Double Buffering)
	return 0;
}

int vid_resize(int width, int height)
{
	if (height==0)
	{
		height=1;
	}

	glViewport(0,0,width,height);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	gluPerspective(90/*config->getValue("vid_fov").asNumber*/,(GLfloat)width/(GLfloat)height,0.1f,100.0f);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	com_print("Resized window: %dx%d", width, height);
	return 0;
}